#include "APP_BT.h"

//接收蓝牙回应 成功 0 失败-1
static int Wait_ACK(Device* device)
{
    usleep(50 * 1000);//等待50ms,等对方发送回应
    //确保的当前蓝牙在非阻塞状态下执行
    char cmd[32] = {0};
    read(device->fd,cmd,4);
    if(memcmp(cmd,"OK\r\n",4) == 0)
    {
        return 0;
    }
    return -1;
}

//测试设备 串口与蓝牙的连通性  成功 0 失败 1
static int APP_BT_Status(Device* device)
{
    write(device->fd,"AT\r\n",4);
    return Wait_ACK(device);
}

//设置蓝牙的波特率
static int APP_BT_Baudrate(Device* device,BTBaudRate baudrate)
{
    char cmd[32] = {0};
    sprintf(cmd,"AT+BAUD%c\r\n",baudrate);
    write(device->fd,cmd,strlen(cmd));
    return Wait_ACK(device);
}

//设置蓝牙的组网ID
static int APP_BT_Netid(Device* device,char* netid)
{
    char cmd[32] = {0};
    sprintf(cmd,"AT+NETID%s\r\n",netid);
    write(device->fd,cmd,strlen(cmd));
    return Wait_ACK(device);
}
//设置蓝牙的短地址
static int APP_BT_Maddr(Device* device,char* maddr)
{
    char cmd[32]={0};
    sprintf(cmd, "AT+MADDR%s\r\n", maddr);
    write(device->fd, cmd, strlen(cmd));
    return Wait_ACK(device);
}
//设置蓝牙的名字
static int APP_BT_Name(Device* device,char* name)
{
    char cmd[32]={0};
    sprintf(cmd, "AT+NAME%s\r\n", name);
    write(device->fd, cmd, strlen(cmd));
    return Wait_ACK(device);
}
//重启蓝牙芯片
static int APP_BT_Reset(Device* device)
{
    write(device->fd,"AT+RESET\r\n",10);
    return Wait_ACK(device);
}

static int APP_BT_Config(Device* device)
{
    log_info("蓝牙基础配置开始");
    //串口进入非阻塞模式
    APP_Serial_Block(device,0);
    //先将串口的波特率降为9600
    APP_Serial_Baudrate(device,BR_9600);
    tcflush(device->fd,TCIOFLUSH);
    //与蓝牙进行 连通性测试
    if(APP_BT_Status(device) == 0)
    {
        //若测试通过 则将蓝牙波特率改为115200 并重启
        int r = APP_BT_Baudrate(device,BT_BAUD_115200);
        if(r == 0)
        {
            log_info("蓝牙波特率设置成功");
        }
        r = APP_BT_Reset(device);
        if(r == 0)
        {
            log_info("蓝牙模块成功重启");
        }
        sleep(2);
    }
    //最后将串口波特率改为 115200  调用flush刷写进去
    APP_Serial_Baudrate(device,BR_115200);
    tcflush(device->fd,TCIOFLUSH);

    //蓝牙组网ID
    int r = APP_BT_Netid(device,"0054");
    if(r == 0)
    {
        log_info("蓝牙组网ID设置成功");
    }
    //蓝牙短地址
    r = APP_BT_Maddr(device,"0778");
    if(r == 0)
    {
        log_info("蓝牙短地址成功");
    }
    //蓝牙名字
    r = APP_BT_Name(device,"Su_da");
    if(r == 0)
    {
        log_info("蓝牙名字设置成功");
    }
    //串口进入 阻塞模式
    APP_Serial_Block(device,1);
    tcflush(device->fd,TCIOFLUSH);
    log_info("蓝牙基础配置结束");
    return 0;
}


//初始化蓝牙配置
void APP_BT_Init(Device* device)
{
    //配置设备当前连接类型
    device->Conn_type = conn_bt;
    //装配数据接收后函数
    device->post_read = APP_BT_Post_read;
    //装配数据接收前函数
    device->pre_write = APP_BT_Pre_Write;
    //蓝牙设备本身的初始化配置
    APP_BT_Config(device);
}

/**
 * 从设备读取数据后处理数据来满足网关应用的要求
 * 接收方得到数据1（4）：ok\r\n
 * 接收方得到数据2（3 + [2]）：f1 dd 07 23 23 ff ff 41 42 43
    f1 dd : 固定的头部
    07： 之后数据的长度（5-16之间） 
    23 23：对端（发送方）的MADDR
    ff ff: 我的MADDR或ffff(群发)
    41 42 43：发送的数据 
 * 处理后的数据格式：conn_type id_len msg_len id msg
 */

//蓝牙读取数据格式 -> 字节数组   成功返回 转换后的数据长度  失败 -1

static char recv_buff[100] = {0};//接收到数据的缓存
static int recv_len = 0;//上次缓存的长度
static char data_head[2] = {0xf1,0xdd};

//将位于offset开头的所有数据 往左边移动到最左边 消除offset前面的所有数据
static void left_move_data(int offset)
{//偏移量最大为 数据总长度
    if(offset > recv_len)
    {
        offset = recv_len;        
    }
    // 目标地址   源地址  源地址想要整体复制移动的长度
    memmove(recv_buff,(recv_buff + offset),(recv_len - offset));
    //更新移动后数据总长度
    recv_len -= offset;
}
int APP_BT_Post_read(Device* device,char* data,int len)
{
    log_info("接收对端数据格式 -> 字节数组格式");
    //将读取到数据存入 缓存中
    memcpy(recv_buff + recv_len,data,len);
    recv_len += len;
    //对缓存数据的判断 1.收到完整数据帧:(OK\r\n) 2.收到完整的目标数据帧(f1 dd xx xx xx ) //3.收到垃圾数据帧 (xx xx xx OK\r\n) 或者 (xx xx xx f1 dd)
    
    //0.读取到数据长度 不足 最低长度4 (OK\r\n) 直接跳出函数
    if(recv_len < 4)
    {
        return 0;
    }
    //1.收到垃圾数据帧 (xx xx xx OK\r\n) 或者 (xx xx xx f1 dd) 
    for(int i = 0;i < recv_len;i++)
    {
        if(memcmp((recv_buff + i),data_head,2) == 0 || memcmp((recv_buff + i),"OK\r\n",4) == 0)
        {
            left_move_data(i);
            break;
        }
    }
    //2.收到完整数据帧:(OK\r\n) 直接移动该数据长度消除数据
    //将OK\r\n 和 f1 dd前面的垃圾数据移动消除
    if(memcmp((recv_buff),"OK\r\n",4) == 0)
    {
        left_move_data(4);
    }
    //3.收到完整的目标数据帧(f1 dd xx xx xx ) 开始解析提取数据转化为 字节数组 并清除 缓存数据
    if(memcmp((recv_buff),data_head,2) == 0)
    {
        //完整的一个数据帧至少有一个一个数据 也就是 f1 dd 07 23 23 ff ff xx 8个数据
        if(recv_len > 8)
        {
            //后续消息内容客观应该有的数据长度 
            int data_remain_len = recv_buff[2];
            //判断实际与客观应该的长度来决定是否解析此次数据
            if((recv_len - 3) >= data_remain_len)
            {
                data[0] = conn_bt;
                data[1] = 2;
                data[2] = data_remain_len - 4;
                //id内容
                memcpy((data + 3),recv_buff + 3,2);
                //数据内容
                memcpy((data + 5),recv_buff + 7,(data_remain_len - 4));
                //清除缓冲区中此次解析出来的数据
                left_move_data(data_remain_len + 3);

                //最终获得字节数组的长度
                int size = data_remain_len + 1;
                log_info("接收对端数据解析字节数组:");
                hexstr_print(data,size);
                log_info("字节数组长度为: %d",size);
                return size;
            }
        }
    }
    //返回长度 0
    return 0;
}

//  * 准备向设备写前处理数据来满足蓝牙发送数据的要求
//  * 当前data: conn_type id_len msg_len id msg (01 02 03 ff ff 11 22 33)
//  * 蓝牙发送数据格式: 
//  示例：41 54 2b 4d 45 53 48 00 ff ff 41 42 43 0d 0a
//         41 54 2b 4d 45 53 48 00： AT+MESH（固定头部）
//         ff ff: 对端的MADDR（如果是FFFF代表群发）
//         11 22 33: 要发送的数据（不超过12字节）
//         0d 0a：\r\n（固定结尾）
//  */
//字节数组 -> 蓝牙发送数据格式   成功返回 转换后的数据长度  失败 -1
int APP_BT_Pre_Write(Device* device,char* data,int len)
{
    log_info("字节数组格式 -> 发送对端数据格式");
    //定义数据帧头
    char send_data[32] = "AT+MESH ";
    //赋值
    memcpy(send_data + 8,data + 3,2);//对端设备地址
    memcpy(send_data + 10,data + 5,data[2]);//具体数据内容
    memcpy(send_data + 10 + data[2],"\r\n",2);//  \r\n 结束符

    int send_len = 12 + data[2];
    //将输入进来的 data改写成蓝牙发送数据格式
    memcpy(data,send_data,send_len);
    data[send_len] = '\0';
    log_info("发送前数据:");
    hexstr_print(data,send_len);
    return send_len;//返回更改格式后的长度
}
